package com.fs.base.utils;

import java.lang.reflect.Array;
import java.net.InetAddress;
import java.util.ArrayList;
import java.util.List;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import javax.servlet.http.HttpServletRequest;

import org.apache.commons.lang3.StringUtils;
import org.apache.log4j.LogManager;
import org.apache.log4j.Logger;
import org.springframework.beans.factory.DisposableBean;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.context.annotation.Lazy;
import org.springframework.stereotype.Component;
import org.springframework.ui.Model;
import org.springframework.web.context.request.RequestAttributes;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;
import org.springframework.web.servlet.mvc.support.RedirectAttributes;

/**
 * <p>Created by Raofeicheng on 2016-10-22.</p>
 * @author Raofeicheng
 * @version 1.0
 */
@Component
@Lazy(false)
public class ServletUtils implements ApplicationContextAware, DisposableBean {

	/**
	 * 获取当前Request
	 */
	public static HttpServletRequest getRequest() {
		RequestAttributes requestAttributes = RequestContextHolder.getRequestAttributes();
		if (null == requestAttributes) return null;
		if (!(requestAttributes instanceof ServletRequestAttributes)) return null;
		return ((ServletRequestAttributes) requestAttributes).getRequest();
	}

	/**
	 * 获取ContextPath
	 */
	public static String getContextPath() {
		return getContextPath(getRequest());
	}

	/**
	 * 获取ContextPath
	 */
	public static String getContextPath(HttpServletRequest request) {
		if (null == request) request = getRequest();
		String path = request.getContextPath();
		if ("/".equals(path)) path = "";
		return path;
	}

	/**
	 * 获取客户端IP地址
	 */
	public static String getClientIP() {
		return getClientIP(getRequest());
	}

	/**
	 * 获取客户端IP地址
	 */
	public static String getClientIP(HttpServletRequest request) {
		String ip = request.getHeader("X-Forwarded-For");
		if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip))
			ip = request.getHeader("Proxy-Client-IP");
		if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip))
			ip = request.getHeader("WL-Proxy-Client-IP");
		if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip))
			ip = request.getHeader("HTTP_CLIENT_IP");
		if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip))
			ip = request.getHeader("HTTP_X_FORWARDED_FOR");
		if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip))
			ip = request.getRemoteAddr();
		//获取本机真是IP
		if (ip.equals("127.0.0.1")) {
			InetAddress inet = null;
			try {
				inet = InetAddress.getLocalHost();
			} catch (Exception e) {
			}
			if (null != inet) ip = inet.getHostAddress();
		}
		//如果有多个代理，第一个IP为真实客户端IP
		if (null != ip && ip.length() > 15) {
			String re = "((((\\d{1,2})|(1\\d{2})|(2[0-4]\\d)|(25[0-5]))\\.){3}((1\\d{2})|(2[0-4]\\d)|(25[0-5])|(\\d{1,2})))";
			Pattern pattern = Pattern.compile(re);
			Matcher matcher = pattern.matcher(ip);
			if (matcher.find()) ip = matcher.group(1);
		}
		return ip;
	}

	public static String getCompleteHost(boolean containContextPath) {
		return getCompleteHost(getRequest(), containContextPath);
	}

	public static String getCompleteHost(HttpServletRequest request, boolean containContextPath) {
		String port = request.getServerPort() + "", ctx = containContextPath ? getContextPath(request) : "";
		if (StringUtils.equals(port, "80")) port = "";
		if (StringUtils.isNotBlank(port)) port = ":" + port;
		return String.format("%s://%s%s%s", request.getScheme(), request.getServerName(), port, ctx);
	}

	/**
	 * 是否是Ajax异步请求
	 */
	public static boolean isAjax(HttpServletRequest request) {
		String accept = request.getHeader("accept");
		String xRequestedWith = request.getHeader("X-Requested-With");
		// 如果是异步请求或是手机端，则直接返回信息
		return accept != null && accept.indexOf("application/json") != -1
			|| (xRequestedWith != null && xRequestedWith.indexOf("XMLHttpRequest") != -1);
	}

	public static boolean isGet(HttpServletRequest request) {
		return StringUtils.equalsIgnoreCase("GET", request.getMethod());
	}

	public static void addMessage(Model model, String... messages) {
		model.addAttribute("message", StringUtils.join(messages, "<br/>"));
	}

	public static void addMessage(RedirectAttributes redirectAttributes, String... messages) {
		redirectAttributes.addFlashAttribute("message", StringUtils.join(messages, "<br/>"));
	}

	/**
	 * 取得存储在静态变量中的ApplicationContext.
	 */
	public static ApplicationContext getApplicationContext() {
		assertContextInjected();
		return applicationContext;
	}

	/**
	 * 从静态变量applicationContext中取得Bean, 自动转型为所赋值对象的类型.
	 */
	@SuppressWarnings("unchecked")
	public static <T> T getBean(String name) {
		assertContextInjected();
		return (T) applicationContext.getBean(name);
	}

	/**
	 * 从静态变量applicationContext中取得Bean, 自动转型为所赋值对象的类型.
	 */
	public static <T> T getBean(Class<T> requiredType) {
		assertContextInjected();
		return applicationContext.getBean(requiredType);
	}

	/**
	 * 从静态变量applicationContext中取得Bean, 自动转型为所赋值对象的类型.
	 */
	public static <T> T[] getBeans(Class<T> clazz) {
		assertContextInjected();
		List<T> list = new ArrayList<T>();
		for (String beanName : getBeanNames(clazz)) {
			list.add(applicationContext.getBean(beanName, clazz));
		}
		return list.toArray((T[]) Array.newInstance(clazz, list.size()));
	}

	/**
	 * 从静态变量applicationContext中取得BeanId
	 */
	public static String[] getBeanNames(Class<?> clazz) {
		assertContextInjected();
		return applicationContext.getBeanNamesForType(clazz);
	}

	/**
	 * 清除ServletUtils中的ApplicationContext为Null.
	 */
	public static void clearHolder() {
		if (logger.isDebugEnabled()) {
			logger.debug("清除ServletUtils中的ApplicationContext:" + applicationContext);
		}
		applicationContext = null;
	}

	/**
	 * 实现ApplicationContextAware接口, 注入Context到静态变量中.
	 */
	public void setApplicationContext(ApplicationContext applicationContext) {
		ServletUtils.applicationContext = applicationContext;
	}

	/**
	 * 实现DisposableBean接口, 在Context关闭时清理静态变量.
	 */
	public void destroy() throws Exception {
		clearHolder();
	}

	/**
	 * 检查ApplicationContext不为空.
	 */
	private static void assertContextInjected() {
		if (applicationContext != null) return;
		throw ExceptionUtils.newRuntimeException("applicaitonContext属性未注入, 请在applicationContext.xml中定义ServletUtils.");
	}

	private static ApplicationContext applicationContext = null;

	private static Logger logger = LogManager.getLogger(ServletUtils.class);

}
